﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace ExpressionTreeLib
{
    public class ExpressionNodeTypeMapping
    {
        private static readonly Dictionary<Type, Type> _mapping;

        public static Dictionary<Type, Type> Mapping
        {
            get { return _mapping; }
        }

        static ExpressionNodeTypeMapping()
        {
            _mapping = new Dictionary<Type, Type>();
            foreach (var type in typeof(ExpressionNodeTypeMapping).Assembly.GetTypes())
            {
                if( !typeof(NodeViewModel).IsAssignableFrom(type))
                    continue;

                var atts = type.GetCustomAttributes(typeof (ExpressionTypeAttribute), true).OfType<ExpressionTypeAttribute>();

                foreach (var expressionTypeAttribute in atts)
                {
                    _mapping.Add(expressionTypeAttribute.ExpressionType, type);
                }
            }
        }

        public static NodeViewModel Create(Expression expressionNode, NodeViewModel parentNode)
        {
            var nodeType = expressionNode == null
                               ? typeof (NodeViewModel.EmptyViewModel)
                               : FindMappingViewModelType(expressionNode.GetType());

            var nvm = Activator.CreateInstance(nodeType) as NodeViewModel;
            nvm.LoadExpressionNode(expressionNode);

            if( parentNode != null )
            {
                parentNode.Children.Add(nvm);
                nvm.Parent = parentNode;
            }

            return nvm;
        }

        public static Type FindMappingViewModelType(Type expressionNodeClrType)
        {
            Type nvmType;
            while (!_mapping.TryGetValue(expressionNodeClrType, out nvmType))
            {
                expressionNodeClrType = expressionNodeClrType.BaseType;
            }
            return nvmType;
        }
    }
}
